<?php
/**
 * [2012-03-25][Milo Liu] Add the master/slaver support into DAO
 * [2012-03-25][Milo Liu] Hide all origial operations of PDO interal, 
 * And all database operaion will be only allowed by calling the query and the exec  methods of this class
 */
class Dao {
    private $_fields;
    private $_primary;
    private $_table;
    private $_valueClass;
    private $_dbConfigKey;
    private $_pdos;
    private $_masterPdo;
    private $_slaverPdo;
    private $_initFlag = false;

    public function __construct($table, $pdos) {
        $this->_table = $table;
        $this->_pdos = $pdos;

        $this->_masterPdo = $pdos[DB_LB_MASTER];
        $this->_slaverPdo = isset($pdos[DB_LB_SLAVER])?$pdos[DB_LB_SLAVER][0]:$this->_masterPdo;
    }


    public function init(){
        if(!$this->_initFlag){
            $fields = $this->query("describe {$table}", null, PDO::FETCH_ASSOC);

            $this->_fields = array();
            foreach ($fields as $field) {
                if (!$this->_primary && $field["Key"] == "PRI") {
                    $this->_primary = $field["Field"];
                }
                $this->_fields[] = $field["Field"];
            }
            $this->_valueClass = str_replace(" ", "", ucwords(str_replace("_", " ", $table)));
            $classFile = DAO_VOCLASS_PATH."/value/{$this->_valueClass}.class.php";
            if (file_exists($classFile)) {
                require_once($classFile);
            }
            $this->_initFlag=true;
        }

    }

    public function query($sql, $binds=array(), $fetchMode=PDO::FETCH_BOTH) {
        DaoFactory::log($sql . print_r($binds, true)  . "\n");

        try{

            $statement = $this->_slaverPdo->prepare($sql);

            if(is_array($binds)){
                foreach($binds as $field => $value){
                    $field = is_numeric($field)?$field+1:$field;
                    $statement->bindValue($field, $value);
                }
            }

            $statement->execute();

            $result = $statement->fetchAll($fetchMode);

            $statement->closeCursor();
            unset($statement);

            return $result;

        }catch(PDOException $e){
            die($e->getMessage());
        }
    }

    public function exec($sql,$binds=array()) {
        DaoFactory::log($sql . "\n");

        try{

            $statement = $this->_masterPdo->prepare($sql);

            if(is_array($binds)){
                foreach($binds as $field => $value){
                    $field = is_numeric($field)?$field+1:$field;
                    $statement->bindValue($field, $value);
                }
            }


            $result = $statement->execute();

            $statement->closeCursor();
            unset($statement);

            return $result;

        }catch(PDOException $e){
            die($e->getMessage());
        }   DaoFactory::toLog($sql . "\n");
    }


    private function _genSql($where) {
        $fieldsStr = implode(",", $this->_fields);
        return "select {$fieldsStr} from {$this->_table} where {$where}";
    }



    public function fetch($where, $bind=array()) {
        $sql = $this->_genSql($where);

        DaoFactory::log($sql . print_r($binds, true)  . "\n");

        try{

            $statement = $this->_slaverPdo->prepare($sql);

            if(is_array($binds)){
                foreach($binds as $field => $value){
                    $field = is_numeric($field)?$field+1:$field;
                    $statement->bindValue($field, $value);
                }
            }

            $statement->execute();

            $className = "Value";
            if (class_exists($this->_valueClass)) {
                $className = $this->_valueClass;
            }

            $statement->setFetchMode(PDO::FETCH_CLASS, $className);
            $value = $statement->fetch();

            $statement->closeCursor();
            unset($statement);
            if (!$value) {
                return false;
            }

            $value->setTable($this->_table);
            $value->setFields($this->_fields);
            $value->setPrimary($this->_primary);
            $value->setDao($this);

            return $value;


        }catch(PDOException $e){
            die($e->getMessage());
        }
    }

    public function fetchAll($where) {
        $sql = $this->_genSql($where);

        DaoFactory::log($sql . print_r($binds, true)  . "\n");

        try{

            $statement = $this->_slaverPdo->prepare($sql);

            if(is_array($binds)){
                foreach($binds as $field => $value){
                    $field = is_numeric($field)?$field+1:$field;
                    $statement->bindValue($field, $value);
                }
            }

            $statement->execute();

            $className = "Value";
            if (class_exists($this->_valueClass)) {
                $className = $this->_valueClass;
            }

            $statement->setFetchMode(PDO::FETCH_CLASS, $className);
            $values = $statement->fetchAll();

            $statement->closeCursor();
            unset($statement);
            if (!$values) {
                return false;
            }
            $vos = array();
            foreach($values as $value){

                $value->setTable($this->_table);
                $value->setFields($this->_fields);
                $value->setPrimary($this->_primary);
                $value->setDao($this);
                $vos[] = $value;
            }
            return $vos;

        }catch(PDOException $e){
            die($e->getMessage());
        } 
    }

    public function fetchAllPage($where, $page, $pagesize, $binds=array()) {
        $rowCount = $this->getRowCount($where, $binds);
        $pageCount = ceil($rowCount/$pagesize);
        $startRow = ($page-1)*$pagesize;
        $where .= " limit {$startRow}, {$pagesize}";
        $data = $this->fetchAll($where, $binds);
        $returnArray = array();
        $returnArray["page"] = $page;
        $returnArray["pagesize"] = $pagesize;
        $returnArray["pageCount"] = $pageCount;
        $returnArray["rowCount"] = $rowCount;
        $returnArray['pages'] = ($pageCount > 1) ? range(1, $pageCount) : array(1);
        $returnArray["data"] = $data;
        return $returnArray;
    }

    public function getRowCount($where, $binds) {
        $sql = "select count(1) from {$this->_table} where {$where}";
        $result = $this->query($sql, $binds, PDO::FETCH_ASSOC);
        $rowCount = $result[0][0];
        return $rowCount;
    }

    public function getEmptyValue() {
        $className = "Value";
        if (class_exists($this->_valueClass)) {
            $className = $this->_valueClass;
        }
        $value = new $className();
        $value->setTable($this->_table);
        $value->setFields($this->_fields);
        $value->setPrimary($this->_primary);
        $value->setDao($this);
        return $value;
    }

    public function getByPrimary($value) {
        $where = "{$this->_primary} = ?";
        return $this->fetch($where, array($value));
    }

    public function lastInsertId(){
        $this->_masterPdo->lastInsertId();
    }
}

